
//1  范型与继承
// 例子：
// 写法一：
// interface T {
//   length: number,
// }
// interface childT extends T {
//    name: string,
//  }

// 写法二：
// type aT = {
//   length: number,
// };

// type bT = {
//   name: string,
// };

// type T = aT & bT;


// (1)
function getLen<T extends string | any[] >(args: T): number {
  return args.length;
};
// console.log(getLen('hello'));
// console.log(getLen([1, 2, 3]));

// (2)
function getLen2<T extends {length: number} >(args: T): number {
  return args.length;
};
// console.log(getLen2('hello22222'));
// console.log(getLen2([1, 2, 3]));

// (3)
interface Len {
  length: number,
}
function getLen3<T extends Len >(args: T): number {
  return args.length;
};
// console.log(getLen3('hello22222'));
// console.log(getLen3([1, 2, 3]));

// (4)
type TLen = {
  length: number,
}
function getLen4<T extends TLen>(args: T): number {
  return args.length;
};
console.log(getLen4<string>('hello22222'));
console.log(getLen4<any[]>([1, 2, 3]));


//2 范型与类
// 写法一：
class UserCls <T>{
  private data: T[] = [];
  constructor() { };
  addUer(user: T): boolean {
    this.data.push(user);
    return true;
  };
  getOne(): T {
    return this.data.shift();
  };
  showall(): T[] {
    return this.data;
  }
};
type user = {
  name: string,
  age: number,
  [value: string]: any,
}
let instance: UserCls<user> = new UserCls<user>();
instance.addUer({
  name: 'zml',
  age: 34,
  sex: 1,
});
instance.addUer({
  name: 'xiaoh',
  age: 39,
  sex: 0,
});
// console.log(instance.getOne());
// console.log(instance.showall());

// 写法二：
class User2<T> {
  constructor(protected data: T[]) { };
  adduser(...users: T[]): boolean {
    this.data.push(...users);
    return true;
  };
  showUsers(): T[] {
    return this.data;
  }
}
interface userI {
  name: string,
  age: number,
}
let instance2 = new User2<userI>([]);
instance2.adduser({
  name: 'swk',
  age: 800,
}, {
  name: 'zbj',
  age: 600,
});
console.log(instance2.showUsers());











//4 类的修饰符
type userType = {
    name: string,
    age: number,
    sex: number,
}
// 父类
class ParentCls{
  public name: string = 'initName';
  protected age: number = 0;
  private sex: number = 0;
  constructor(user: userType) {
    this.name = user.name;
    this.age = user.age;
    this.sex = user.sex;''
  }
  private info(): string {
    return `我是${this.name}今年${this.age}岁，是个${this.sex ? '男' : '女'}孩子`
  };
  public getInfo(): string{
   return this.info();
  };
  protected _setSex(sex: number) {
    this.sex = sex;
  };
  protected _getSex(sex: number) {
    return this.sex;
  };
}

let person1 = new ParentCls({
  name: 'zhanhgsan',
  age: 23,
  sex: 1,
});
// console.log(person1.getInfo());

//子类
class ChildCls extends ParentCls{
  // 子类中对父类修饰属性进行更改只能改的更宽松
  public age: number;
  constructor(user: userType) {
    super(user);
    this.name = user.name;
    this.age = user.age;
    super._setSex(user.sex);
  };
  childMethods(): string {
    return 'childMethod';
  };
  // 子类不能复写父类的方法
  // info() {
  //   console.log('test');
  // }

};

let person2 = new ChildCls({
  name: 'wuwu',
  age: 65,
  sex: 0,
});
console.log(person2.getInfo());
console.log(person2.childMethods());


//5 类的修饰符--readonly妙用
// 该属性只读无法修改，但是可以在改造函数中修改
class Axios {
  public readonly site: string = 'www.baidu.com';
  constructor(site: string) {
    this.site = site || this.site;
  }
  getUrl(): string {
    return `您请求的额地址是：${this.site}`;
  }
};
let axios = new Axios('www.chaojin.cn');
// axios.site = 'www.chaojin.cn';
console.log(axios.getUrl());



// 6.static静态属性
// 单例实现
class Axios2 {
  private static instance: Axios2 | null = null;
  private constructor() {
   console.log('构造函数');
  };
  static make(): Axios2 {
    if (!Axios2.instance) {
      Axios2.instance = new Axios2();
    };
    return Axios2.instance;
  };
}

let axios2 = Axios2.make();
let axios22 = Axios2.make();



// 7. get set 访问器 需要编译成es5 ---    tsc -target es5 
type list = {
  name: string,
  checked: boolean,
}
class Test2 {
  private _lists: list[] = [];
  constructor(...list: list[]) {
    this._lists = list;
  };
  public get lists() {
    console.log('get------');
    return this._lists[this._lists.length - 1];
  };
  public set lists(val: list) {
    console.log('set------');
      this._lists.push(val);
  }
}

let testInstance2 = new Test2({name:'zhang1', checked: false});
testInstance2.lists = {name:'zhang2', checked: true}
console.log(testInstance2.lists);


// 8.抽象类
abstract class Common {
  abstract name: string;
  abstract getName():string;
  public setName(name: string): string {
    this.name = name;
    return this.name;
  }
}
class child1 extends  Common{
  public name: string;
  public getName(): string {
    return this.name;
  };
}

let instance3  = new child1();
console.log(instance3.setName('小名'));

// 9.抽象类和接口混合使用
abstract class common2 {
  set(sex: number): number | void {
    console.log('设置sex：', sex);
  };
}
enum Color {
  red,
  agreen,
  blue
}
interface comInterface {
   color: Color,
   get: (number?: number) => any;
};

class child2 extends common2 implements comInterface {
   color: Color.agreen;
   get():any {
     console.log('child2---get');
   };
}

let instance4 = new child2();
instance4.get();
instance4.set(1);
